#ifndef SCANNER_H_
#define SCANNER_H_
#include <stdio.h>
#include "debug.h"

#ifndef SCANRUNS
# define SCANRUNS 10
#endif
/*
 * define the data types used for lexing and parsing
 */

#define SCANNER_SRCTYPE_UNKNOWN 0
#define SCANNER_SRCTYPE_STRING 1
#define SCANNER_SRCTYPE_FILE 2

typedef enum _scanner_lexem_type {
	UNKNOWN,
	INTEGER,
	DOUBLE,
	LABEL,
	STRING,
	OPERATOR
} scanner_lexem_type;


typedef struct _scanner_state {
	unsigned char src_type;//one of SCANNER_SRCTYPE_*
	char* cursor;//the cursor used by the scanner 
	char* line_begin;//a pointer to the beginning of the current line
//	FILE *f;//not used. use mmap instead
	size_t lineno;//these two are used for error reporting
	size_t colno;
	char error;
} scanner_state;

typedef struct _token_value {
	scanner_lexem_type type;
	size_t line_no;
	size_t col_no;
	union val {
		struct {
			char *val;
			size_t len;//for strings, labels (function/variable identifiers)
		} str;
		long long int i;//for integer constants
		//numeric constants:
		//TODO: make them platform-independent
		double d;//for double constants
	} val;
} token_value;

#define SCANNER_TOKEN_DUMP(tok) \
	switch((tok).type) { \
		case UNKNOWN: \
			DEBUG_SCANNER1("TOKEN\ttype: UNKNOWN, line: %d, column: %d",(tok).line_no,(tok).col_no); \
			break; \
		case DOUBLE: \
			DEBUG_SCANNER1("TOKEN\ttype: DOUBLE, value: %f, at col/no %d/%d",(tok).val.d,(tok).line_no,(tok).col_no); \
			break; \
		case INTEGER: \
			DEBUG_SCANNER1("TOKEN\ttype: INTEGER, value: %f, at col/no %d/%d",(tok).val.d,(tok).line_no,(tok).col_no); \
			break; \
		case LABEL: \
			DEBUG_SCANNER1("TOKEN\ttype: LABEL, value: \"%s\", at col/no %d/%d",(tok).val.str.val,(tok).line_no,(tok).col_no); \
			break; \
		case OPERATOR: \
			DEBUG_SCANNER1("TOKEN\ttype: OPERATOR, at col/no %d/%d",(tok).line_no,(tok).col_no); \
			break; \
		default: \
			DEBUG_SCANNER1("TOKEN\tERROR - unhandled in %s on line %d",__FILE__,__LINE__); \
	}
/*
 * macros to work with these structures
 *
 * we don't do it manually for the purpose of easy extensibility
 *
 * NOTE: for pointers, "state" or "token" must be dereferenced accordingly
 */

int scan(scanner_state *state,token_value **token);

#define SCANNER_INIT(scanner) (scanner).cursor = NULL; \
			(scanner).lineno = 1; (scanner).colno = 1; \
			(scanner).error = 0
//syncs values like line_no and col_no
#define SCANNER_SYNC_STATE_TOKEN(scanner,token) ((token).line_no) = ((scanner).lineno); ((token).col_no) = ((scanner).colno)

#define SCANNER_STATE_NEXTLINE(state,linep) (((state).lineno)++); (state).line_begin = (linep); (state).colno = 0
#define SCANNER_STATE_COLUMN(state) (((state).colno))
#define SCANNER_STATE_SET_SRCTYPE(state,type) ((state).src_type) = (type)
#define SCANNER_STATE_SET_FILE(state,filep)	((state).f) = (filep); \
						SCANNER_STATE_SET_SRCTYPE(state,SCANNER_SRCTYPE_FILE)

#define SCANNER_STATE_GET_SRCTYPE(state) ((state).src_type)
#define SCANNER_STATE_GET_FILE(state) ((state).f)

#define SCANNER_STATE_SET_STRING(state,s)	((state).cursor) = (s); (state).line_begin = (s); \
						SCANNER_STATE_SET_SRCTYPE(state,SCANNER_SRCTYPE_STRING)
#define SCANNER_STATE_GET_STRING(state)		((state).cursor)


#endif
